#include <nice2d/components/attributetable.h>

class AttributeTableData
{
public:
    std::map<uint32_t, int32_t> data;
};

AttributeTable1D::AttributeTable1D():
    data(new AttributeTableData())
{
}

AttributeTable1D::~AttributeTable1D()
{
}

void AttributeTable1D::add(int32_t key, int32_t value)
{
    auto node = std::make_pair(key, value);
    data->data.insert(node);
}

std::optional<int32_t> AttributeTable1D::get(int32_t key)
{
    auto find = data->data.find(key);
    return find == data->data.end() ? std::optional<int32_t>() : find->second;
}

AttributeTable2D::AttributeTable2D():
    data(new AttributeTableData())
{
}

AttributeTable2D::~AttributeTable2D()
{
}

void AttributeTable2D::add(int32_t key1, int32_t key2, int32_t value)
{
    int32_t key = (key1 << 16) | key2;
    data->data.insert_or_assign(key, value);
}

std::optional<int32_t> AttributeTable2D::get(int32_t key1, int32_t key2)
{
    int32_t key = (key1 << 16) | key2;
    auto itr = data->data.find(key);
    if (itr == data->data.end())
        return std::optional<int32_t>();
    return itr->second;
}

AttributeTable3D::AttributeTable3D():
    data(new AttributeTableData())
{
}

AttributeTable3D::~AttributeTable3D()
{
}

void AttributeTable3D::add(uint8_t spriteType, uint8_t tileType, uint8_t attributeType,
                           int32_t value)
{
    int32_t key = (spriteType << 16) + (tileType << 8) + attributeType;
    data->data.insert_or_assign(key, value);
}

std::optional<int32_t> AttributeTable3D::get(uint8_t spriteType, uint8_t tileType,
                                             uint8_t attributeType)
{
    int32_t key = (spriteType << 16) + (tileType << 8) + attributeType;
    auto itr = data->data.find(key);
    if (itr == data->data.end())
        return std::optional<int32_t>();
    return itr->second;
}

#define DEFINE_ATTRIBUTE_TABLE_SERIALIZE(target)\
PTree target::serialize()\
{\
    PTree node;\
    std::for_each(data->data.begin(), data->data.end(), [&](const auto & item) {\
        PTree current;\
        current.add("key", item.first);\
        current.add("value", item.second);\
        node.add_child("item", current);\
    });\
    return node;\
}\
void target::deserialize(const PTree &node)\
{\
    auto itr = node.begin();\
    while(itr != node.end())\
    {\
        auto tag = itr->first;\
        auto current = itr->second;\
        if(tag == "item")\
        {\
            uint32_t key = current.get<uint32_t>("key");\
            int32_t value = current.get<int32_t>("value");\
            data->data.insert(std::make_pair(key,value));\
        }\
        itr ++;\
    }\
}

DEFINE_ATTRIBUTE_TABLE_SERIALIZE(AttributeTable1D)
DEFINE_ATTRIBUTE_TABLE_SERIALIZE(AttributeTable2D)
DEFINE_ATTRIBUTE_TABLE_SERIALIZE(AttributeTable3D)
